#!/usr/bin/python
# -*- coding: UTF-8 

import os
import glob
import sys
import time
import getopt
from enum import Enum
import  socket

# 枚举的使用
class CommandType(Enum):
    git_commit = 1 << 0
    git_push = 1 << 1
    git_all = (1 << 2) - 1
    all = git_all

    def valid(self, desType):
    	return self.value & desType.value == desType.value


class AutoSyncItem:
	def __init__(self, path, interval = 5):
		self.path = path
		self.name = os.path.basename(self.path)
		self.interval = interval
		self.allowedCommand = CommandType.git_commit
		self.idx = 0  # 索引

	def __str__(self):
		return 'path: %s interval:%d allowedCommand:%d' % (self.path, self.interval, self.allowedCommand.value)


class AutoSyncToGitTool:
	def __init__(self):
		self.pwd = os.getcwd()
		self.items = []
		self.commandType = CommandType.git_commit
		self.showDialog = False
		self.logDir = os.path.join(self.pwd, '.log')
		self.logPath = '%s%s' % (time.strftime('%Y-%m-%d-%H', time.localtime()), '.log')
		if not os.path.exists(self.logDir):
			os.makedirs(self.logDir)


	def start(self):
		for idx, item in enumerate(self.items):
			item.idx = idx + 1
			self.autoStart(item)

	def autoStart(self, item):
		fo = open(os.path.join(self.logDir, self.logPath), "a+")
		log_start = "%s %s %s\n" % ('#'*30, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) ,'#'*30)
		fo.write(log_start)
		fo.write('------------- path %03d  ' % item.idx + item.path + ' ---------------- \n')
		if self.commandType.valid(CommandType.git_commit) and item.allowedCommand.valid(CommandType.git_commit):
			fo.write('==== executing git status ... \n' + self.git_status(item) + '\n')
			fo.write('==== executing git add ... \n' + self.git_add(item) + '\n')
			fo.write('==== executing git commit ... \n' + self.git_commit(item) + '\n')
		else:
			fo.write('==== executing git commit refused \n')

		if self.commandType.valid(CommandType.git_push) and item.allowedCommand.valid(CommandType.git_push):
			if self.git_pre_push_check(item) == True:
				fo.write('==== executing git push ... \n' + self.git_push(item) + '\n')
			else:
				fo.write('==== executing git push failed waiting for personal handle ... \n')
		else:
			fo.write('==== executing git push refused \n')

		if self.git_pre_pull_check(item) == True:
			fo.write('==== executing git pull ... \n' + self.git_pull(item) + '\n')
		else:
			fo.write('==== executing git pull failed waiting for personal handle ... \n')

		fo.write('\n')
		# 关闭打开的文件 
		fo.close()

	# 弹出提示框
	def show_dialog_tips(self, item):
		if self.showDialog == True:
			command = 'osascript ./show_dialog.applescript %s \"%s\"' % (item.name + '有冲突，需手动更新处理', 'open %s' % item.path)
			self.command(command)

	# pull 前 check
	def git_pre_pull_check(self, item):
		text = self.git_status(item)
		shouldPull = False
		if "is behind" in text: # 本地比远端要新，可以直接 push
			shouldPull = True
		elif "different commits each" in text: # 远端有更新，本地有未提交的修改，需要手动解决
			self.show_dialog_tips(item)
		return shouldPull

	# push 前 check
	def git_pre_push_check(self, item):
		text = self.git_status(item)
		shouldPush = False
		if "is ahead of" in text: # 本地比远端要新，可以直接 push
			shouldPush = True
		elif "different commits each" in text: # 远端有更新，本地有未提交的修改，需要手动解决
			self.show_dialog_tips(item)
		return shouldPush

	# 执行 git pull --rebase
	def git_pull(self, item):
		command = 'cd %s && git pull --rebase' % item.path
		return self.command(command)	

	# 执行 git push
	def git_push(self, item):
		command = 'cd %s && git push' % item.path
		return self.command(command)

	# 执行 git commit
	def git_commit(self, item):
		command = 'cd %s && git commit -m \"auto sync at %s\"' % (item.path, time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
		return self.command(command)

	# 执行 git add
	def git_add(self, item):
		command = 'cd %s && git add .' % item.path
		return self.command(command)

	# 执行 git status
	def git_status(self, item):
		command = 'cd %s && git status' % item.path
		return self.command(command)

	# 执行命令，并获取结果
	def command(self, command):
		result = os.popen(command)
		text = result.read()
		result.close()
		return text

class DeviceInfo:
	host_name = socket.gethostname()

#######################  一款没有任何副作用的自动同步工具  #####################
'''  ⚠️ ⚠️ ⚠️ 基于 Git 仓库实现，仅用于个人文件同步，开发项目谨慎使用  ⚠️ ⚠️ ⚠️
0. 脚本下载后，放在任意目录下
1》执行 generate_crontab_task_template.sh 生成 crontab 配置文件
2》修改 auto_sync_to_git.py 配置需要同步的 git 仓库本地目录； 
3》执行 ./auto_sync_start.sh 即可

1. 设置需要自动同步的 git 目录
2. 设置是允许的操作，默认只支持本地 commit
3. 通过 crontab_task.sh 配合，设置同步的频率 (目前只支持所有目录采用同一个频率)
4. 操作日志存储在，脚本所在目录下的 .log 目录下，每小时产生一个文件
'''
##########################################################################
if __name__ == '__main__': 
	
	syncTool = AutoSyncToGitTool()
	
	if 'MacBook-Air' in DeviceInfo.host_name:
		syncTool.showDialog = True

	print(DeviceInfo.host_name);

	# 配置需要同步的 仓库
	syncItem02 = AutoSyncItem('/Users/zljiao/study-notes')
	syncItem02.allowedCommand = CommandType.git_all
	syncTool.items.append(syncItem02)
	
	def tips(code):
		os.system("echo \"\033[36;36m Error Code: %s \033[0m\"" % str(code))
		os.system("echo \"\033[36;36m Usage: \033[0m\"")
		print(' -h[--help]: 获取帮助信息')
		print(' -c[--commit]: 仅 commit 到本地仓库')
		print(' -push[--push]: 仅 push 本地仓库到远端')
		print(' -all[--all]: 相当于 commit + push 的效果')
		sys.exit()

	try:
	    opts, args = getopt.getopt(sys.argv[1:], "hcpax:", ["help", "commit", "push", "all", "x="])
	    print("opts: ", opts, "args: ", args)
	except getopt.GetoptError:
		tips(1)

	if len(args):
		tips(2)

	for opt, arg in opts:
	        if opt in ("-h", "--help"):
	            tips(3)
	        elif opt in ("-c", "--commit"):
	        	print(opt)
	        	syncTool.commandType = CommandType.git_commit
	        elif opt in ("-p", "--push"):
	        	print(opt)
	        	syncTool.commandType = CommandType.git_push
	        elif opt in ("-a", "--all"):
	        	print(opt)
	        	syncTool.commandType = CommandType.all
	        else:
	        	print("no match")
	        	syncTool.commandType = CommandType.git_commit
 
	print("start... ", syncTool.commandType)
	print("start...")
	syncTool.start()

	